﻿using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using Behaviorize.Model.CodeInterpretation;
using Behaviorize.Model.CodeMerging;
using Behaviorize.Model.CodeModel;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using VSLangProj80;

namespace Behaviorize
{
	[PackageRegistration(UseManagedResourcesOnly = true)]
	// This attribute is used to register the informations needed to show the this package
	// in the Help/About dialog of Visual Studio.
	[InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
	[Guid(GuidList.guidBehaviorize_PkgString)]
	[ComVisible(true)]
	[CodeGeneratorRegistration(typeof(CodeGenerator), "Behaviorize", vsContextGuids.vsContextGuidVCSProject, GeneratesDesignTimeSource = true)]
	public class CodeGenerator : Package, IVsSingleFileGenerator
	{
		private const string FileExtension = ".feature.cs";

		public int DefaultExtension(out string pbstrDefaultExtension)
		{
			pbstrDefaultExtension = FileExtension;
			return pbstrDefaultExtension.Length;
		}

		public int Generate(string wszInputFilePath, string bstrInputFileContents, string wszDefaultNamespace, IntPtr[] rgbOutputFileContents, out uint pcbOutput, IVsGeneratorProgress pGenerateProgress)
		{
			string existingCode = GetExistingCode(wszInputFilePath);
			string code = GetScenarioCode(bstrInputFileContents, existingCode, wszDefaultNamespace);
			var bytes = Encoding.Unicode.GetBytes(code);
			var length = bytes.Length;

			rgbOutputFileContents[0] = Marshal.AllocCoTaskMem(length);
			Marshal.Copy(bytes, 0, rgbOutputFileContents[0], length);

			pcbOutput = (uint)length;

			return 0;
		}

		private static string CreateStubCode(string defaultNamespace, Feature feature)
		{
			return
				String.Format(@"namespace {0}
{{
	[TestClass]
	public class {1}
	{{

	}}
}}", defaultNamespace, feature.Name.AsPascal());
		}

		public static string GetScenarioCode(string sourceSpecification, string existingCode, string defaultNamespace)
		{
			Feature feature = Interpreter.ParseSpecificationText(sourceSpecification, defaultNamespace);
			CodeUpdater codeUpdater = new CodeUpdater(existingCode ?? CreateStubCode(defaultNamespace, feature), feature);
			return codeUpdater.UpdateCode();
		}

		private static string GetExistingCode(string filePath)
		{
			return !File.Exists(filePath + FileExtension) ? null : File.ReadAllText(filePath + FileExtension);
		}
	}
}